﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using NClass.DiagramEditor;
using System;
using System.Collections.Generic;
using NClass.AssemblyImport;
using NClass.CodeGenerator;
using NClass.TestHelper;
using NClass.Core;
using System.IO;
using NReflect;
using System.Linq;

namespace NClass.Test.AssemblyImport
{
    [TestClass]
    public class AssemblyImportRelationshipTest : BaseCodeGenerationTest
    {
        protected override string ActualDirectory
        {
            get { return @"AssemblyImportRelationshipTest\ActualResults"; }
        }

        protected override string ExpectedDirectory
        {
            get { return @"..\..\AssemblyImport\ExpectedResults"; }
        }

        [TestMethod]
        [TestCategoryAttribute("Assembly Import")]
        public void SimpleImportAssemblyRelationship()
        {
            DiagramEditor.ClassDiagram.Diagram classDiagram =  ReflectAssembly(@"..\..\..\SimpleImportAssembly\bin\Debug\SimpleImportAssembly.dll");

            Assert.AreEqual<int>(3, classDiagram.Relationships.Count());
            foreach (var relationship in classDiagram.Relationships)
            {
                Assert.AreEqual<RelationshipType>(RelationshipType.Generalization, relationship.RelationshipType);
                Assert.AreEqual<string>("Animal", relationship.Second.Name);
            }

            Assert.IsTrue(classDiagram.Relationships.Where(relationship => relationship.First.Name == "Cat").Count() == 1);
            Assert.IsTrue(classDiagram.Relationships.Where(relationship => relationship.First.Name == "Cow").Count() == 1);
            Assert.IsTrue(classDiagram.Relationships.Where(relationship => relationship.First.Name == "Dog").Count() == 1);
        }

        [TestMethod]
        [TestCategoryAttribute("Assembly Import")]
        public void NestedImportAssemblyRelationship()
        {
            DiagramEditor.ClassDiagram.Diagram classDiagram = ReflectAssembly(@"..\..\..\NestedImportAssembly\bin\Debug\NestedImportAssembly.dll");

            Assert.AreEqual<int>(1, classDiagram.Relationships.Count());

            Assert.AreEqual<RelationshipType>(RelationshipType.Nesting, classDiagram.Relationships.First().RelationshipType);
            Assert.AreEqual<string>("ParentClass", classDiagram.Relationships.First().First.Name);
            Assert.AreEqual<string>("ChildClass", classDiagram.Relationships.First().Second.Name);
        }

        [TestMethod]
        [TestCategoryAttribute("Assembly Import")]
        public void ComplexImportAssemblyRelationship()
        {
            DiagramEditor.ClassDiagram.Diagram classDiagram = ReflectAssembly(@"..\..\..\ComplexAssemblyImport\bin\Debug\ComplexAssemblyImport.dll");

            Assert.AreEqual<int>(2, classDiagram.Relationships.Count());

            Assert.IsTrue(classDiagram.Relationships.Where(relationship => relationship.RelationshipType == RelationshipType.Realization).Count() == 1);
            Assert.IsTrue(classDiagram.Relationships.Where(relationship => relationship.RelationshipType == RelationshipType.Association).Count() == 1);

            Relationship realizationRelationship = classDiagram.Relationships.Where(relationship => relationship.RelationshipType == RelationshipType.Realization).First();
            Assert.AreEqual<string>(realizationRelationship.First.Name, "ConcreteWorker");
            Assert.AreEqual<string>(realizationRelationship.Second.Name, "IInterface");

            AssociationRelationship associationRelationship = classDiagram.Relationships.Where(relationship => relationship.RelationshipType == RelationshipType.Association).First() as AssociationRelationship;

            Assert.AreEqual<string>(associationRelationship.First.Name, "Order");
            Assert.AreEqual<string>(associationRelationship.Second.Name, "OrderLine");
            Assert.IsNull(associationRelationship.StartMultiplicity);
            Assert.AreEqual<string>(associationRelationship.EndMultiplicity, "*");
            Assert.AreEqual<string>(associationRelationship.StartRole, "orderLines");
            Assert.IsNull(associationRelationship.EndRole);
        }

        [TestMethod]
        [TestCategoryAttribute("Assembly Import")]
        public void BasicAssemblyImportTest()
        {
            ImportAssembly(@"..\..\..\SimpleImportAssembly\bin\Debug\SimpleImportAssembly.dll", "SimpleImportAssembly");
        }

        [TestMethod]
        [TestCategoryAttribute("Assembly Import")]
        public void NestedAssemblyImportTest()
        {
            ImportAssembly(@"..\..\..\NestedImportAssembly\bin\Debug\NestedImportAssembly.dll", "NestedImportAssembly");
        }

        [TestMethod]
        [TestCategoryAttribute("Assembly Import")]
        public void ComplexAssemblyImportTest()
        {
            ImportAssembly(@"..\..\..\ComplexAssemblyImport\bin\Debug\ComplexAssemblyImport.dll", "ComplexAssemblyImport");
        }

        private DiagramEditor.ClassDiagram.Diagram ReflectAssembly(string pathToAssembly)
        {

            ImportSettings settings = new ImportSettings
            {
                CreateAssociations = true,
                CreateGeneralizations = true,
                CreateNestings = true,
                CreateRealizations = true,
                CreateRelationships = true
            };

            settings.FilterRules = new List<NReflect.Filter.FilterRule>();
            DiagramEditor.ClassDiagram.Diagram classDiagram = new DiagramEditor.ClassDiagram.Diagram(Resolver.GetLanguage(Resolver.GetResolverLanguage(Resolver.Language.CSharp)));
            NETImport importer = new NETImport(
                    classDiagram,
                    settings
                    );

            importer.ImportAssembly(pathToAssembly);
            return classDiagram;
        }

        private void ImportAssembly(string pathToAssembly, string projectName)
        {
            Resolver.Language language = Resolver.GetResolverLanguage(Resolver.Language.CSharp);
            DiagramEditor.ClassDiagram.Diagram classDiagram = ReflectAssembly(pathToAssembly);

            // Prep output directory
            var outputDirectory = PrepareGenerationOutputDirectory(language, projectName);

            var myProject = new Project(projectName);
            myProject.Add(classDiagram);
            classDiagram.Name = projectName;


            //make a file generator to output some sort of result
            Generator codeGenerator = new Generator(myProject, SolutionType.VisualStudio2008);
            GenerationResult result = codeGenerator.Generate(outputDirectory);

            var errorMessage = string.Empty;
            Assert.IsTrue(ValidateOutput(language, projectName, out errorMessage),
                string.Format("AssemblyImportRelationshipTest." + projectName + "() -> {0}", errorMessage));
        }
    }
}
